#pragma once
#include "DataStructure/Common/Out.h"
#include "Utility/Algebra/Matrix.h"
#include "Utility/Algebra/Vector3D.h"
#include "Utility/Algebra/Point.h"
#include "DataStructure/Common/Id.h"
#include "DataStructure/Input/Node/NodeData.h"
#include "DataStructure/Input/Element/CBARData.h"
#include "DataStructure/Input/Material/IsotropicMaterial.h"
#include "DataStructure/Input/Property/PBARData.h"
#include "../Common/ElementCalculatorExport.h"
#include "../Interface/IElementCalculator.h"

SG_FEMSOLVER_ELEMENT_NAMESPACE_OPEN

class ElementCalculator_DECLSPEC BarCalculator : public SG::FEMSolver::Element::IElementCalculator
{
public:
    BarCalculator () = default;
    virtual ~BarCalculator () = default;

    /** @brief 计算 Basic 坐标系下梁单元的朝向矢量
     * 
     *  @param [in] orienNode 朝向节点数据
     *  @param [in] orienFlag 朝向矢量坐标系 Flag
     *  @param [in] pointA 节点 A 在 Basic 坐标系下的坐标
     *  @param [in] dispCoordIdA 节点 A 的位移输出坐标系 Id
     *  @param [in] TGA 节点 A 的位移输出坐标系变换矩阵
     *  @param [in, out] orienVector 朝向矢量
    */
    static void ComputeOrienVector
    (
    const SG::DataStructure::FEM::NodeData&        orienNode,
    const SG::DataStructure::FEM::BeamCoordOptions orienFlag,
    const SG::Algebra::Point&                      pointA,
    const SG::DataStructure::Common::Id            dispCoordIdA,
    const SG::Algebra::Matrixd&                    TGA,
    _OUT SG::Algebra::Vector3D&                    orienVector
    );

    /** @brief 节点偏置矢量变换到 Basic 坐标系和位移输出坐标系（G）
     * 
     *  @param [in] offsetFlagSet 单元偏置 Flag
     *  @param [in] TO 偏置坐标系的变换矩阵
     *  @param [in] dispCoordIdSet 单元节点的位移输出坐标系 Id
     *  @param [in] TGSet 单元节点的位移输出坐标系变换矩阵
     *  @param [in, out] offsetSet 原始偏置矢量、Basic 坐标系偏置矢量
     *  @param [out] offsetSetG 位移输出坐标系（G）偏置矢量
     */
    static void ComputeOffset
    (
    const std::vector<SG::DataStructure::FEM::BeamCoordOptions>& offsetFlagSet,
    const SG::Algebra::Matrixd&                                  TO,
    const SG::DataStructure::Common::IdArray&                    dispCoordIdSet,
    const std::vector<SG::Algebra::Matrixd>&                     TGSet,
    _OUT std::vector<SG::Algebra::Vector3D>&                     offsetSet,
    _OUT std::vector<SG::Algebra::Vector3D>&                     offsetSetG
    );

    /** @brief 组装单元变换矩阵
     * 
     *  @param [in] T 单元坐标系的变换矩阵
     *  @param [in] dispCoordIdSet 单元节点的位移输出坐标系 Id
     *  @param [in] TGSet 单元节点的位移输出坐标系变换矩阵
     *  @param [in] offsetSetG 位移输出坐标系下的偏置矢量
     *  @param [out] TEle 单元变换矩阵：单元坐标系到位移输出坐标系变换 + 偏置变换
    */
    static void AssembleElementTrans
    (
    const SG::Algebra::Matrixd&               T,
    const SG::DataStructure::Common::IdArray& dispCoordIdSet,
    const std::vector<SG::Algebra::Matrixd>&  TGSet,
    const std::vector<SG::Algebra::Vector3D>& offsetSetG,
    _OUT SG::Algebra::Matrixd&                TEle
    );

    /** @brief 计算单元长度、单元坐标系变换矩阵和单元变换矩阵
     * 
     *  @param [in] element 单元数据
     *  @param [in] nodeSet 单元节点数据
     *  @param [in] orienNode 单元朝向节点数据，如果使用朝向节点
     *  @param [out] L 偏置后单元长度
     *  @param [out] T 单元坐标系变换矩阵
     *  @param [out] TEle 单元变换矩阵：单元坐标系到位移输出坐标系变换 + 偏置变换
     */
    static void ComputeElementTrans
    (
    const SG::DataStructure::FEM::CBARData&              element,
    const std::vector<SG::DataStructure::FEM::NodeData>& nodeSet,
    const SG::DataStructure::FEM::NodeData&              orienNode,
    _OUT SG::DataStructure::Common::Real&                L,
    _OUT SG::Algebra::Matrixd&                           T,
    _OUT SG::Algebra::Matrixd&                           TEle
    );

    /** @brief 计算单元坐标系下单元刚度矩阵
     * 
     * @param [in] L 偏置后单元长度
     * @param [in] material 材料属性
     * @param [in] property 单元属性
     * @param [out] kl 单元坐标系下单元刚度矩阵
    */
    static void ComputeStiffness
    (
    const SG::DataStructure::Common::Real&           L,
    const SG::DataStructure::FEM::IsotropicMaterial& material,
    const SG::DataStructure::FEM::PBARData&          property,
    _OUT SG::Algebra::Matrixd&                       kl
    );

    /** @brief 计算单元坐标系下单元集中质量矩阵
     *  @param [in] hasTorsion 是否考虑转动项
     *  @param [in] L 偏置后单元长度
     *  @param [in] rho 材料密度
     *  @param [in] property 单元属性
     *  @return 单元坐标系下单元集中质量矩阵
    */
    static SG::Algebra::Matrixd ComputeLumpedMass
    (
    const bool                              hasTorsion,
    const SG::DataStructure::Common::Real&  L,
    const SG::DataStructure::Common::Real&  rho,
    const SG::DataStructure::FEM::PBARData& property
    );

     /** @brief 计算单元坐标系下单元耦合质量矩阵
     *  @param [in] isBARMASS 是否需要一致质量矩阵
     *  @param [in] L 偏置后单元长度
     *  @param [in] rho 材料密度
     *  @param [in] property 单元属性
     *  @return 单元坐标系下单元耦合质量矩阵
    */
    static SG::Algebra::Matrixd ComputeCoupledMass
    (
    const bool                              isBARMASS,
    const SG::DataStructure::Common::Real&  L,
    const SG::DataStructure::Common::Real&  rho,
    const SG::DataStructure::FEM::PBARData& property
    );

    /** @brief 单元坐标系单元质量矩阵的自由度释放
     * 
     *  @param [in] freeDofSet 释放的单元自由度
     *  @param [in] kl 未自由度释放的单元坐标系单元刚度矩阵
     *  @param [in, out] ml 单元坐标系单元质量矩阵
    */
    static void ReleaseMassDof (const std::vector<std::size_t>& freeDofSet, const SG::Algebra::Matrixd& kl, _OUT SG::Algebra::Matrixd& ml);

    /** @brief 单元坐标系单元刚度矩阵的自由度释放
     * 
     *  @param [in] freeDofSet 释放的单元自由度
     *  @param [in, out] kl 单元坐标系单元刚度矩阵
    */
    static void ReleaseStiffnessDof (const std::vector<std::size_t>& freeDofSet, _OUT SG::Algebra::Matrixd& kl);

    /**
     * @brief    计算自由度释放的荷载矩阵，大小(12,1)
     *           其被Pload1Calc调用
     * 
     * @param    dofsPaRelease      左节点释放自由度集
     * @param    dofsPbRelease      右节点释放自由度集
     * @param    stiffMat           单元刚度矩阵
     * @param    loadMat            荷载矩阵
     * @author   Liu Xing
     * @date     2025.08.23
     */
    static void ReleaseLoadDof
    (
    const SG::DataStructure::FEM::DofSet& dofsPaRelease,
    const SG::DataStructure::FEM::DofSet& dofsPbRelease,
    SG::Algebra::Matrixd&                 stiffMat,
    _OUT SG::Algebra::Matrixd&            loadMat
    );

    /**
     * @brief 计算梁单元内力
     * 
     * @param [in] kl 自由度释放后的单元坐标系单元刚度矩阵
     * @param [in] TEle 单元变换矩阵：单元坐标系到位移输出坐标系变换 + 偏置变换
     * @param [in] elementDisplacement 位移输出坐标系单元位移
     * @param [out] elementInternalForce 梁单元内力
     */
    static void ComputeElementInternalForce
    (
    const SG::Algebra::Matrixd& kl,
    const SG::Algebra::Matrixd& TEle,
    const SG::Algebra::Matrixd& elementDisplacement,
    _OUT SG::Algebra::Matrixd&  elementInternalForce
    );

    /**
     * @brief 计算梁单元应力：单元轴向正应力和截面应力恢复点处由弯曲产生的轴向正应力
     * 
     * @param [in] elementInternalForce 单元内力
     * @param [in] property 单元属性
     * @param [out] elementStress 轴向正应力和截面应力恢复点处由弯曲产生的轴向正应力
     */
    static void ComputeElementStress
    (
    const SG::Algebra::Matrixd&             elementInternalForce,
    const SG::DataStructure::FEM::PBARData& property,
    _OUT SG::Algebra::Matrixd&              elementStress
    );

    /**
     * @brief    计算单元应变
     * 
     * @param    elementStress 单元应力：单元轴向正应力和截面应力恢复点处由弯曲产生的轴向正应力
     * @param    E 材料杨氏模量
     * @param    elementStrain 单元应变
     * @author   Du Weixing
     * @date     2024.12.19
     */
    static void ComputeElementStrain
    (
    const SG::Algebra::Matrixd&            elementStress,
    const SG::DataStructure::Common::Real& E,
    _OUT SG::Algebra::Matrixd&             elementStrain
    );

    /**
     * @brief    计算bar单元坐标转换矩阵、荷载转换矩阵、单元长度
     *           其被Pload1Calc调用
     * 
     * @param    dbServiceFactory 
     * @param    barData 
     * @param    TEle 
     * @param    T 
     * @param    L 
     * @author   Liu Xing
     * @date     2025.08.23
     */
    static void BarCoorTrans
    (
    const SG::DBManager::DBServiceFactorySP dbServiceFactory,
    const SG::DataStructure::FEM::CBARData& barData,
    _OUT SG::Algebra::Matrixd&              TEle,
    _OUT SG::Algebra::Matrixd&              T,
    _OUT SG::DataStructure::Common::Real&   L
    );

    virtual void Initialize (SG::DataStructure::FEM::ElementTypes type) override;
    virtual void ComputeElementMatries (const SG::DBManager::DBServiceFactorySP dbServiceFactory) override;
    virtual void DataRecovery (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int subcaseId, SG::DataStructure::Common::Real time, const std::vector<SG::DataStructure::Common::Real>& globalDisplacement) override;
    virtual void ComputeStressStiffness (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int staticSubId) override;

    static ElementCalculatorSP Create () {return std::make_shared<BarCalculator> ();}

private:
    SG::DataStructure::FEM::ElementTypes m_type;
};

SG_FEMSOLVER_ELEMENT_NAMESPACE_CLOSE